#include "include/nsd_windows/nsd_windows_plugin.h"

#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")

// This must be included before many other Windows headers.
#include <windows.h>

// For getPlatformVersion; remove unless needed for your plugin implementation.
#include <VersionHelpers.h>

#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>

#include <codecvt>
#include <map>
#include <memory>
#include <sstream>

#include <windns.h>
#pragma comment(lib, "dnsapi.lib")
#pragma warning( \
    disable : 4018 4189 4244 4267 4456 4458 4496 4551 4616 4701 4996)
namespace {
// Converts the given UTF-8 string to UTF-16.
std::wstring Utf16FromUtf8(const std::string& utf8_string) {
  if (utf8_string.empty()) {
    return std::wstring();
  }
  int target_length =
      ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(),
                            static_cast<int>(utf8_string.length()), nullptr, 0);
  if (target_length == 0) {
    return std::wstring();
  }
  std::wstring utf16_string;
  utf16_string.resize(target_length);
  int converted_length =
      ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(),
                            static_cast<int>(utf8_string.length()),
                            utf16_string.data(), target_length);
  if (converted_length == 0) {
    return std::wstring();
  }
  return utf16_string;
}

std::string Utf8FromUtf16(std::wstring& wide) {
  // std::string str;
  // std::transform(wide.begin(), wide.end(), std::back_inserter(str),
  // [](wchar_t c) {
  //  return (char)c;
  //});
  // std::string str(wide.length(), 0);
  // std::transform(wide.begin(), wide.end(), str.begin(), [](wchar_t c) {
  //  return (char)c;
  //  });

  // setup converter
  using convert_type = std::codecvt_utf8<TCHAR>;
  std::wstring_convert<convert_type, TCHAR> converter;

  // use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
  std::string converted_str = converter.to_bytes(wide);

  return converted_str;
}

template <class T>
T GetArgument(const flutter::EncodableMap arguments,
              const std::string key = "handle") {
  T value;
  // const auto* arguments =
  // std::get_if<flutter::EncodableMap>(method_call.arguments());
  auto it = arguments.find(key);
  if (it != arguments.end()) {
    if (it->second.IsNull()) {
      if (typeid(T) == typeid(flutter::EncodableMap) ||
          typeid(T) == typeid(flutter::EncodableList)) {
        value = {};
      } else if (typeid(T) == typeid(std::string)) {
        value = T();
      }
    } else {
      value = std::get<T>(it->second);
    }
  } else {
  }
  return value;
}

class NsdWindowsPlugin : public flutter::Plugin {
 public:
  static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar);
  static std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>>
      methodChannel;
  static NsdWindowsPlugin instance;

  NsdWindowsPlugin();

  virtual ~NsdWindowsPlugin();

 protected:
  static void browseCallback(const DWORD status,
                             void* context,
                             DNS_RECORD* records);
  static void resolveCompletionCallback(const DWORD status,
                                        void* context,
                                        DNS_SERVICE_INSTANCE* instance);
  static void callbackRegisterComplete(const DWORD status,
                                       void* context,
                                       DNS_SERVICE_INSTANCE* instance);
  static std::map<std::string, bool> serviceNameMap;
  static std::vector<flutter::EncodableMap> registerQueue;
  static void startRegister(flutter::EncodableMap arguments);
  static std::map<std::string, std::unique_ptr<DNS_SERVICE_CANCEL>>
      cancelRegisterMap;
  static std::map<std::string, flutter::EncodableMap> registeredServiceMap;
  bool valid;

 private:
  // Called when a method is called on this plugin's channel from Dart.
  void HandleMethodCall(
      const flutter::MethodCall<flutter::EncodableValue>& method_call,
      std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);

  DWORD unregister(
      const flutter::MethodCall<flutter::EncodableValue>& method_call);
  void startBrowser(
      const flutter::MethodCall<flutter::EncodableValue>& method_call,
      std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
  DWORD stopBrowser(
      const flutter::MethodCall<flutter::EncodableValue>& method_callt);
  void startResolver(
      const flutter::MethodCall<flutter::EncodableValue>& method_call,
      std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
  DWORD stopResolver(
      const flutter::MethodCall<flutter::EncodableValue>& method_call);

  std::map<std::string, std::unique_ptr<DNS_SERVICE_CANCEL>> cancelBrowserMap =
      {};
  std::map<std::string, std::unique_ptr<DNS_SERVICE_CANCEL>> cancelResolverMap =
      {};
  std::map<std::string, std::unique_ptr<DNS_SERVICE_CANCEL>> handleMap = {};
};

// static
void NsdWindowsPlugin::RegisterWithRegistrar(
    flutter::PluginRegistrarWindows* registrar) {
  methodChannel =
      std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
          registrar->messenger(), "com.haberey/nsd",
          &flutter::StandardMethodCodec::GetInstance());

  auto plugin = std::make_unique<NsdWindowsPlugin>();

  methodChannel->SetMethodCallHandler(
      [plugin_pointer = plugin.get()](const auto& call, auto result) {
        plugin_pointer->HandleMethodCall(call, std::move(result));
      });
  registrar->AddPlugin(std::move(plugin));
}

std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>>
    NsdWindowsPlugin::methodChannel;
std::map<std::string, bool> NsdWindowsPlugin::serviceNameMap;
std::vector<flutter::EncodableMap> NsdWindowsPlugin::registerQueue = {};
std::map<std::string, std::unique_ptr<DNS_SERVICE_CANCEL>>
    NsdWindowsPlugin::cancelRegisterMap;
std::map<std::string, flutter::EncodableMap>
    NsdWindowsPlugin::registeredServiceMap;

void NsdWindowsPlugin::callbackRegisterComplete(
    const DWORD status,
    void* context,
    DNS_SERVICE_INSTANCE* instance) {
  if (instance) {
  }

  if (status == ERROR_CANCELLED) {
    return;
  }

  if (status != ERROR_SUCCESS) {
  }
  auto* arguments = static_cast<flutter::EncodableMap*>(context);
  NsdWindowsPlugin::methodChannel->InvokeMethod(
      "onRegistrationSuccessful",
      std::make_unique<flutter::EncodableValue>(*arguments));
  NsdWindowsPlugin::registerQueue.erase(
      NsdWindowsPlugin::registerQueue.begin());
  if (NsdWindowsPlugin::registerQueue.size() > 0) {
    flutter::EncodableMap next = NsdWindowsPlugin::registerQueue[0];
    NsdWindowsPlugin::startRegister(next);
  }
}
void NsdWindowsPlugin::browseCallback(const DWORD status,
                                      void* context,
                                      DNS_RECORD* records) {
  if (status == ERROR_CANCELLED) {
    return;
  }
  if (status != ERROR_SUCCESS) {
    return;
  }
  std::vector<DNS_RECORD> list;
  std::string* handle = static_cast<std::string*>(context);
  for (auto cur = records; cur; cur = cur->pNext) {
    int dwTtl = cur->dwTtl;
    if (cur->wType != DNS_TYPE_PTR) {
      continue;
    }
    list.push_back(*cur);

    // "_pasteshare._tcp.local".
    const wchar_t* pName = cur->pName;
    std::wstring domainW(pName);
    std::string domain(domainW.begin(), domainW.end());
    // "Test._pasteshare._tcp.local".
    wchar_t* pNameHost = cur->Data.PTR.pNameHost;
    std::wstring hostnameW(pNameHost);
    std::string hostname(hostnameW.begin(), hostnameW.end());
    auto isCached = NsdWindowsPlugin::serviceNameMap.find(hostname);
    if (isCached != NsdWindowsPlugin::serviceNameMap.end()) {
      continue;
    }
    NsdWindowsPlugin::serviceNameMap.insert_or_assign(hostname, true);

    std::string serviceName = hostname.substr(0, hostname.find(domain));

    std::string serviceType = domain.substr(0, domain.rfind('.'));

    NsdWindowsPlugin::methodChannel->InvokeMethod(
        "onServiceDiscovered",
        std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
            {flutter::EncodableValue("handle"),
             flutter::EncodableValue(*handle)},
            {flutter::EncodableValue("service.type"),
             flutter::EncodableValue(serviceType)},
            {flutter::EncodableValue("service.name"),
             flutter::EncodableValue(serviceName)},
            {flutter::EncodableValue("service.host"),
             flutter::EncodableValue(hostname)},
        }));
  }
}
void NsdWindowsPlugin::resolveCompletionCallback(
    const DWORD status,
    void* context,
    DNS_SERVICE_INSTANCE* instance) {
  if (status == ERROR_CANCELLED) {
    return;
  }
  std::string* handle = static_cast<std::string*>(context);
  if (status != ERROR_SUCCESS) {
    NsdWindowsPlugin::methodChannel->InvokeMethod(
        "onResolveFailed",
        std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
            {flutter::EncodableValue("handle"),
             flutter::EncodableValue(*handle)},
            {flutter::EncodableValue("error.cause"),
             flutter::EncodableValue("code:" + status)},
            {flutter::EncodableValue("error.message"),
             flutter::EncodableValue("Refer: "
                                     "https://docs.microsoft.com/en-us/windows/"
                                     "win32/debug/system-error-codes--0-499-")},
        }));
    return;
  }
  flutter::EncodableMap txtMap;
  for (int i = 0; i < instance->dwPropertyCount; i++) {
    wchar_t* keyA = instance->keys[i];
    std::wstring keyW(keyA);
    std::string key(keyW.begin(), keyW.end());
    auto valueA = instance->values[i];
    std::wstring valueAW(valueA);
    std::string valueString = Utf8FromUtf16(valueAW);
    if (valueString == "null") {
      std::monostate null;
      txtMap.insert_or_assign(flutter::EncodableValue(key), null);
      continue;
    }
    std::vector<unsigned char> aTXT;
    for (int i = 0; i < valueString.length(); i++) {
      aTXT.push_back(valueString[i]);
    }
    txtMap.insert_or_assign(flutter::EncodableValue(key),
                            flutter::EncodableValue(aTXT));
  }
  wchar_t* pszHostName = instance->pszHostName;
  std::wstring hostnameW(pszHostName);
  std::string hostname(hostnameW.begin(), hostnameW.end());
  wchar_t* pszInstanceName = instance->pszInstanceName;
  std::wstring instanceNameW(pszInstanceName);
  std::string instanceName = Utf8FromUtf16(instanceNameW);
  std::string local = hostname.substr(hostname.find("."));
  std::string name = instanceName.substr(0, instanceName.find("."));
  std::string serviceType = instanceName.substr(
      name.length() + 1,
      instanceName.length() - local.length() - name.length() - 1);
  NsdWindowsPlugin::methodChannel->InvokeMethod(
      "onResolveSuccessful",
      std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
          {flutter::EncodableValue("handle"), flutter::EncodableValue(*handle)},
          {flutter::EncodableValue("service.type"),
           flutter::EncodableValue(serviceType)},
          {flutter::EncodableValue("service.name"),
           flutter::EncodableValue(name)},
          {flutter::EncodableValue("service.host"),
           flutter::EncodableValue(hostname)},
          {flutter::EncodableValue("service.port"),
           flutter::EncodableValue(instance->wPort)},
          {flutter::EncodableValue("service.txt"), txtMap},
      }));
}

NsdWindowsPlugin::NsdWindowsPlugin() : valid(false) {
  auto handle = GetModuleHandle(L"dnsapi.dll");
  if (handle) {
    if (DnsServiceConstructInstance && DnsServiceFreeInstance &&
        DnsServiceRegister && DnsServiceDeRegister &&
        DnsServiceRegisterCancel) {
      valid = true;
    }
  }
}

NsdWindowsPlugin::~NsdWindowsPlugin() {}

void NsdWindowsPlugin::HandleMethodCall(
    const flutter::MethodCall<flutter::EncodableValue>& method_call,
    std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
  std::string methodName = method_call.method_name();
  if (!valid) {
    result->Error("-1",
                  "Windows Native API not available. Refer: "
                  "https://docs.microsoft.com/en-us/windows/win32/api/windns/");
    return;
  }
  const auto* arguments =
      std::get_if<flutter::EncodableMap>(method_call.arguments());
  if (methodName.compare("startDiscovery") == 0) {
    NsdWindowsPlugin::stopBrowser(method_call);
    NsdWindowsPlugin::startBrowser(method_call, std::move(result));
  } else if (methodName.compare("stopDiscovery") == 0) {
    auto ret = NsdWindowsPlugin::stopBrowser(method_call);
    result->Success(flutter::EncodableValue(NULL));
    if (ret == ERROR_SUCCESS || ret == ERROR_CANCELLED) {
      auto handle = GetArgument<std::string>(*arguments, "handle");
      NsdWindowsPlugin::methodChannel->InvokeMethod(
          "onDiscoveryStopSuccessful",
          std::make_unique<flutter::EncodableValue>(
              flutter::EncodableMap{{flutter::EncodableValue("handle"),
                                     flutter::EncodableValue(handle)}}));
      return;
    }
    result->Error(std::to_string(ret), "");
  } else if (methodName.compare("register") == 0) {
    auto handle = GetArgument<std::string>(*arguments, "handle");
    NsdWindowsPlugin::unregister(method_call);
    registerQueue.push_back(*arguments);
    if (registerQueue.size() == 1) {
      NsdWindowsPlugin::startRegister(*arguments);
    }
    result->Success(NULL);
  } else if (methodName.compare("resolve") == 0) {
    NsdWindowsPlugin::stopResolver(method_call);
    NsdWindowsPlugin::startResolver(method_call, std::move(result));
  } else if (methodName.compare("unregister") == 0) {
    auto ret = NsdWindowsPlugin::unregister(method_call);
    result->Success(flutter::EncodableValue(NULL));
  } else {
    result->NotImplemented();
  }
}

void NsdWindowsPlugin::startRegister(flutter::EncodableMap arguments) {
  std::wstring serviceName =
      Utf16FromUtf8(GetArgument<std::string>(arguments, "service.name"));
  if (serviceName.empty()) {
    DWORD size = 0;
    GetComputerNameEx(ComputerNameDnsHostname, nullptr, &size);
    std::vector<wchar_t> hostname(size);
    if (!GetComputerNameEx(ComputerNameDnsHostname, &hostname[0], &size)) {
      OutputDebugStringA("GetComputerNameEx() failed");
      return;
    }
    serviceName = &hostname[0];
  }

  const std::wstring domain = L".local";
  const auto qualifiedHostname = serviceName + domain;

  std::wstring service = serviceName;
  service += L".";
  std::string serviceType = GetArgument<std::string>(arguments, "service.type");
  service += Utf16FromUtf8(serviceType);
  service += domain;

  flutter::EncodableMap txtMap =
      GetArgument<flutter::EncodableMap>(arguments, "service.txt");
  int dwPropertiesCount = txtMap.size();
  auto it = txtMap.begin();
  std::vector<PCWSTR> keys;
  std::vector<PCWSTR> values;
  while (it != txtMap.end()) {
    auto keyString = std::get<std::string>(it->first);
    auto keyWString = Utf16FromUtf8(keyString);
    const wchar_t* keyCString = keyWString.c_str();
    auto mallocCString = (wchar_t*)malloc(sizeof(wchar_t) * wcslen(keyCString));
    wcscpy(mallocCString, keyCString);
    keys.push_back(mallocCString);

    std::vector<unsigned char> pValueChar;
    if (!(it->second.IsNull())) {
      pValueChar = std::get<std::vector<unsigned char>>(it->second);
      std::string valeString(pValueChar.begin(), pValueChar.end());
      auto valueWString = Utf16FromUtf8(valeString);
      auto valueWCString = valueWString.c_str();
      auto mallocValueWCString =
          (wchar_t*)malloc(sizeof(wchar_t) * wcslen(valueWCString));
      wcscpy(mallocValueWCString, valueWCString);
      values.push_back(mallocValueWCString);
    } else {
      values.push_back(L"null");
    }

    it++;
  }
  auto servicePort = GetArgument<int>(arguments, "service.port");
  auto pServiceInstance = DnsServiceConstructInstance(
      service.c_str(), qualifiedHostname.c_str(), nullptr, nullptr, servicePort,
      0,  //
      0, dwPropertiesCount, dwPropertiesCount == 0 ? nullptr : &keys[0],
      dwPropertiesCount == 0 ? nullptr : &values[0]);

  std::unique_ptr<DNS_SERVICE_REGISTER_REQUEST> pRequest;
  pRequest.reset(new DNS_SERVICE_REGISTER_REQUEST{});
  pRequest->Version = DNS_QUERY_REQUEST_VERSION1;
  pRequest->pServiceInstance = pServiceInstance;
  pRequest->pRegisterCompletionCallback = callbackRegisterComplete;
  std::string handle = GetArgument<std::string>(arguments, "handle");
  flutter::EncodableMap* queryContext = new flutter::EncodableMap(arguments);
  pRequest->pQueryContext = queryContext;

  std::unique_ptr<DNS_SERVICE_CANCEL> registerCancel;
  registerCancel.reset(new DNS_SERVICE_CANCEL{});
  const auto ret = DnsServiceRegister(pRequest.get(), registerCancel.get());
  DnsServiceFreeInstance(pServiceInstance);
  if (ret == DNS_REQUEST_PENDING) {
    cancelRegisterMap.insert_or_assign(handle, std::move(registerCancel));
    NsdWindowsPlugin::registeredServiceMap.insert_or_assign(handle, arguments);
    return;
  }
  NsdWindowsPlugin::methodChannel->InvokeMethod(
      "onRegistrationFailed",
      std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
          {flutter::EncodableValue("handle"), flutter::EncodableValue(handle)},
          {flutter::EncodableValue("error.cause"),
           flutter::EncodableValue("code:" + ret)},
          {flutter::EncodableValue("error.message"),
           flutter::EncodableValue("Refer: "
                                   "https://docs.microsoft.com/en-us/windows/"
                                   "win32/debug/system-error-codes--0-499-")},
      }));
}

DWORD NsdWindowsPlugin::unregister(
    const flutter::MethodCall<flutter::EncodableValue>& method_call) {
  const auto* arguments =
      std::get_if<flutter::EncodableMap>(method_call.arguments());
  std::string handle = GetArgument<std::string>(*arguments, "handle");
  auto it = cancelRegisterMap.find(handle);
  if (it != cancelRegisterMap.end()) {
    auto ret = DnsServiceRegisterCancel(it->second.get());
    if (ret == ERROR_SUCCESS || ret == ERROR_CANCELLED) {
      NsdWindowsPlugin::methodChannel->InvokeMethod(
          "onUnregistrationSuccessful",
          std::make_unique<flutter::EncodableValue>(
              flutter::EncodableMap{{flutter::EncodableValue("handle"),
                                     flutter::EncodableValue(handle)}}));
      auto removedService = NsdWindowsPlugin::registeredServiceMap[handle];
      // removedService.insert_or_assign(flutter::EncodableValue("handle"),
      // NsdWindowsPlugin::test);
      NsdWindowsPlugin::methodChannel->InvokeMethod(
          "onServiceLost",
          std::make_unique<flutter::EncodableValue>(removedService));
      return ret;
    }
    NsdWindowsPlugin::methodChannel->InvokeMethod(
        "onUnregistrationFailed",
        std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
            {flutter::EncodableValue("handle"),
             flutter::EncodableValue(handle)},
            {flutter::EncodableValue("error.cause"),
             flutter::EncodableValue("code:" + ret)},
            {flutter::EncodableValue("error.message"),
             flutter::EncodableValue("Refer: "
                                     "https://docs.microsoft.com/en-us/windows/"
                                     "win32/debug/system-error-codes--0-499-")},
        }));
    return ret;
  }
  return ERROR_SUCCESS;
}

void NsdWindowsPlugin::startBrowser(
    const flutter::MethodCall<flutter::EncodableValue>& method_call,
    std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
  const auto* arguments =
      std::get_if<flutter::EncodableMap>(method_call.arguments());
  std::string handle = GetArgument<std::string>(*arguments, "handle");
  auto queryName =
      GetArgument<std::string>(*arguments, "service.type") + ".local";
  DNS_SERVICE_BROWSE_REQUEST request{};
  request.Version = DNS_QUERY_REQUEST_VERSION1;
  auto queryNameW = Utf16FromUtf8(queryName);
  request.QueryName = reinterpret_cast<LPCWSTR>(queryNameW.c_str());
  request.pBrowseCallback = &NsdWindowsPlugin::browseCallback;
  auto sharedHandle = new std::string(handle);
  request.pQueryContext = sharedHandle;

  std::unique_ptr<DNS_SERVICE_CANCEL> cancelBrowser;
  cancelBrowser.reset(new DNS_SERVICE_CANCEL{});
  const auto ret = DnsServiceBrowse(&request, cancelBrowser.get());
  result->Success(flutter::EncodableValue(NULL));
  if (ret == DNS_REQUEST_PENDING) {
    cancelBrowserMap.insert_or_assign(handle, std::move(cancelBrowser));
    NsdWindowsPlugin::methodChannel->InvokeMethod(
        "onDiscoveryStartSuccessful",
        std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
            {flutter::EncodableValue("handle"),
             flutter::EncodableValue(handle)},
        }));
    return;
  }
  NsdWindowsPlugin::methodChannel->InvokeMethod(
      "onDiscoveryStartFailed",
      std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
          {flutter::EncodableValue("handle"), flutter::EncodableValue(handle)},
          {flutter::EncodableValue("error.cause"),
           flutter::EncodableValue("code:" + ret)},
          {flutter::EncodableValue("error.message"),
           flutter::EncodableValue("Refer: "
                                   "https://docs.microsoft.com/en-us/windows/"
                                   "win32/debug/system-error-codes--0-499-")},
      }));
}

DWORD NsdWindowsPlugin::stopBrowser(
    const flutter::MethodCall<flutter::EncodableValue>& method_call) {
  const auto* arguments =
      std::get_if<flutter::EncodableMap>(method_call.arguments());
  std::string handle = GetArgument<std::string>(*arguments, "handle");
  auto it = cancelBrowserMap.find(handle);
  if (it != cancelBrowserMap.end()) {
    return DnsServiceBrowseCancel(it->second.get());
  }
  return ERROR_SUCCESS;
}

void NsdWindowsPlugin::startResolver(
    const flutter::MethodCall<flutter::EncodableValue>& method_call,
    std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
  const auto* arguments =
      std::get_if<flutter::EncodableMap>(method_call.arguments());
  std::string handle = GetArgument<std::string>(*arguments, "handle");
  auto qualifiedHostname = GetArgument<std::string>(*arguments, "service.host");

  auto context = new std::string(handle);
  OutputDebugStringA("startResolver: ");
  OutputDebugStringA((*context).c_str());
  OutputDebugStringA("\n");
  DNS_SERVICE_CANCEL cancle{context};
  DNS_SERVICE_RESOLVE_REQUEST request{};
  request.Version = DNS_QUERY_REQUEST_VERSION1;
  std::wstring qualifiedHostnameW = Utf16FromUtf8(qualifiedHostname);
  request.QueryName = &qualifiedHostnameW[0];
  request.pResolveCompletionCallback =
      &NsdWindowsPlugin::resolveCompletionCallback;
  request.pQueryContext = context;

  const auto ret = DnsServiceResolve(&request, &cancle);
  if (ret == DNS_REQUEST_PENDING) {
  }
  result->Success(flutter::EncodableValue(NULL));
}

DWORD NsdWindowsPlugin::stopResolver(
    const flutter::MethodCall<flutter::EncodableValue>& method_call) {
  const auto* arguments =
      std::get_if<flutter::EncodableMap>(method_call.arguments());
  std::string handle = GetArgument<std::string>(*arguments, "handle");
  auto it = cancelResolverMap.find(handle);
  if (it != cancelResolverMap.end()) {
    return DnsServiceResolveCancel(it->second.get());
  }
  return ERROR_SUCCESS;
}

}  // namespace

void NsdWindowsPluginRegisterWithRegistrar(
    FlutterDesktopPluginRegistrarRef registrar) {
  NsdWindowsPlugin::RegisterWithRegistrar(
      flutter::PluginRegistrarManager::GetInstance()
          ->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
}
